package com.example.trackcircuitdiagnosis.time;

import com.example.trackcircuitdiagnosis.dto.KGLresDTO;
import com.example.trackcircuitdiagnosis.entity.DataAnalongTableEntity;
import com.example.trackcircuitdiagnosis.entity.DeviceInformationEntity;
import com.example.trackcircuitdiagnosis.service.DataAnalongTableService;
import com.example.trackcircuitdiagnosis.service.DeviceInformationService;
import com.example.trackcircuitdiagnosis.utils.RedisUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 数据处理器，实现了 CommandLineRunner 接口，用于在 Spring Boot 应用启动时执行特定的任务。
 * 该任务包括读取模拟量和开关量数据，处理数据并保存到文件。
 */
@Component
@Order(2)
public class DataProcessor2000R implements CommandLineRunner {

    // Redis 工具类
    @Autowired
    private RedisUtils redisUtils;

    // 从 Excel 读取数据的组件
    @Autowired
    private GetKglDataFromExcel readExcel;


    // ObjectMapper 用于 JSON 处理
    private final ObjectMapper objectMapper = new ObjectMapper();

    // 设备信息服务
    @Autowired
    private DeviceInformationService deviceInformationService;

    // 设备信息列表
    private List<DeviceInformationEntity> deviceInformationEntities;

    // 位置名称与索引的映射表
    private Map<String, Integer> positionIndexMap = new HashMap<>();

    // 文件夹路径
    private String folderPath;


    @Autowired
    private DataAnalongTableService dataAnalongTableService;

    // 保存路径
    private String savePath;

    // 文件读取起始位置
    private final int frequency = 1;
    private final int startNumber = 0;

    private final int deviceNum=549;
    private final int AnalogDataSimulation =10;
    private final int mid=3;

    // 存储模拟量数据的数组
    private float[][] arr;

    // 从 Excel 读取的开关量数据列表
    private List<List<KGLresDTO>> list;

    // 当前环境配置
    @Value("${spring.profiles.active}")
    private String environment;

    // 总长度计数器
    private int totalLength;

    private void init() throws JsonProcessingException {
        initializePositionIndexMap();
        String project="ZPW2000R";
        folderPath = Objects.equals(environment, "dev") ? "D:\\wechatfiles\\WeChat Files\\wxid_u11jgxkukq2o22\\FileStorage\\File\\2023-12\\山市20231219\\wjjc\\historydata\\2023-12-17\\dat2000r\\" : "/home/java/2000rdata/";
        savePath = Objects.equals(environment, "dev") ? "D:\\sb\\2000rdata\\" : "/home/java/2000rdata/";
        arr=new float[86400][deviceNum];

        processFiles(folderPath, startNumber, frequency);
    }

    // 程序运行时的初始化方法
    @Override
    public void run(String... args) throws Exception {

//        init();
//        saveAllData();
    }

    /**
     * 初始化位置名称与索引的映射表
     */
    private void initializePositionIndexMap() {
        List<DataAnalongTableEntity> dataAnalongTableEntities = dataAnalongTableService.dataAnalogALl(mid);

        for (int i = 0; i < dataAnalongTableEntities.size(); i++) {
            String positionName=dataAnalongTableEntities.get(i).getPositionName();
            positionIndexMap.put(positionName, i);
        }
    }

    /**
     * 保存所有数据，包括模拟量和开关量数据
     *
     * @throws IOException 如果发生 I/O 异常
     */
    private void saveAllData() throws IOException {
        deviceInformationEntities = deviceInformationService.findDeviceInformationAll(mid);
        for (int i = 0; i <86400 ; i++) {
            soushuData(i);
            System.out.println(i);
        }
    }

    /**
     * 处理文件夹中的所有文件
     *
     * @param folderPath 文件夹路径
     * @param startNumber 文件读取起始位置
     * @param frequency  文件读取频率
     */
    public void processFiles(String folderPath, int startNumber, int frequency) {
        try {
            Files.walk(Paths.get(folderPath))
                    .filter(Files::isRegularFile)
                    .forEach(file -> handleFile(file, startNumber, frequency));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 处理单个文件
     *
     * @param filePath   文件路径
     * @param startNumber 文件读取起始位置
     * @param frequency  文件读取频率
     */
    private void handleFile(Path filePath, int startNumber, int frequency) {
        processFile(filePath, startNumber, frequency);
        totalLength += calculateRoad(filePath.toString());
    }

    /**
     * 计算文件对应的路数
     *
     * @param filePath 文件路径
     * @return 文件对应的路数
     */
    private int calculateRoad(String filePath) {
        Path file = Paths.get(filePath);
        if (Files.isRegularFile(file) && file.toFile().length() % 86400 == 0) {
            return (int) (file.toFile().length() / 86400 / 2);
        }
        return 0;
    }

    /**
     * 处理单个文件的数据
     *
     * @param filePath   文件路径
     * @param startNumber 文件读取起始位置
     * @param frequency  文件读取频率
     */
    private void processFile(Path filePath, int startNumber, int frequency) {
        int road = calculateRoad(filePath.toString())*2 ;
        try (FileInputStream fis = new FileInputStream(filePath.toString())) {
            byte[] buffer = new byte[road * frequency];
            int bytesRead;
            int count = 0;
            int second = 1;
            while ((bytesRead = fis.read(buffer)) != -1) {
                int binaryDatFileNumber = totalLength;
                for (int i = 0; i+1 < bytesRead; i += 2) {
                        if (binaryDatFileNumber >= startNumber) {
                            processBinaryData(buffer, i, binaryDatFileNumber, second);
                        }
                    binaryDatFileNumber += 1;
                }
                count += bytesRead;

                if (count >= road * frequency) {
                    count = 0;
                    second++;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 处理二进制数据
     *
     * @param buffer              二进制数据缓冲区
     * @param i                   当前处理的位置
     * @param binaryDatFileNumber 当前处理的二进制数据文件编号
     * @param second              当前处理的时间点
     */
    private void processBinaryData(byte[] buffer, int i, int binaryDatFileNumber, int second) {
        ByteBuffer b = ByteBuffer.wrap(buffer, i, 2);
        b.order(ByteOrder.LITTLE_ENDIAN);
        short result = b.getShort();
        float realValue = (float) (result * 0.1);
        try {
            arr[second - 1][binaryDatFileNumber] = realValue;
        } catch (IndexOutOfBoundsException e) {
            System.out.println(second - 1);
            System.out.println(binaryDatFileNumber - 1);
            System.out.println("IndexOutOfBoundsException: " + e.getMessage());
        }
    }



    /**
     * 处理索引对应的数据并生成 JSON 格式的结果，然后将结果写入文件
     *
     * @param index 索引
     * @return 空字符串
     * @throws IOException 如果发生 I/O 异常
     */
    private String soushuData(int index) throws IOException {
        float[] analogData = arr[index];

        // 初始化 JSON 结构
        JsonNode jsonOneObject = createJsonStructure(analogData);

        // 将结果写入文件
        writeToDataFile(objectMapper.writeValueAsString(jsonOneObject), String.valueOf(index+1), savePath);

        return "";
    }

    /**
     * 创建 JSON 结构
     *
     * @param analogData 模拟量数据数组
     * @return JSON 结构
     */
    private JsonNode createJsonStructure(float[] analogData) {
        JsonNodeFactory nodeFactory = JsonNodeFactory.instance;
        ObjectNode jsonOneObject = objectMapper.createObjectNode();

        // 使用 Stream API 按照 did 字段分组
        Map<Integer, List<DeviceInformationEntity>> groupedByDid = deviceInformationEntities.stream()
                .collect(Collectors.groupingBy(DeviceInformationEntity::getDid));

        // 遍历每个分组
        groupedByDid.forEach((did, entities) -> {
            ArrayNode jsonOneArray = nodeFactory.arrayNode();

            // 初始化并放入 2 个值，每个值为 -1
            for (int i = 0; i < AnalogDataSimulation; i++) {
                jsonOneArray.add(-0.1);
            }

            // 填充模拟量数据
            fillAnalogData(jsonOneArray, entities, analogData);


            jsonOneObject.put(String.valueOf(did), jsonOneArray);
        });

        return jsonOneObject;
    }

    /**
     * 填充模拟量数据到 JSON 数组
     *
     * @param jsonOneArray JSON 数组，用于存储模拟量数据
     * @param entities     模拟量数据关联的设备信息列表
     * @param analogData   模拟量数据数组，包含了所有设备在当前时间点的模拟量数据
     */
    private void fillAnalogData(ArrayNode jsonOneArray, List<DeviceInformationEntity> entities, float[] analogData) {

        for (DeviceInformationEntity entity : entities) {
            String positionName = entity.getPositionName();
            if (positionIndexMap.containsKey(positionName)) {
                int jsonIndex = positionIndexMap.get(positionName);
                jsonOneArray.insert(jsonIndex, analogData[entity.getAdNumber()]);
            } else {
                System.out.println("Error: Unknown position name - " + positionName);
            }
        }
    }



    /**
     * 将数据写入文本文件
     *
     * @param data 数据
     * @param name 文件名
     * @param path 保存路径
     * @return 写入是否成功
     * @throws IOException 如果发生 I/O 异常
     */
    public boolean writeToDataFile(String data, String name, String path) throws IOException {
        // 创建文件对象
        File file = new File(path + name + ".txt");

     
        if (file.exists()) {
            boolean delete = file.delete();
        }
        boolean newFile = file.createNewFile();

        // 使用 try-with-resources 语句，确保资源关闭
        try (FileWriter fileWriter = new FileWriter(file.getAbsolutePath(), true);
             BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)) {
            // 将数据写入文件
            bufferedWriter.write(data);
        }

        // 返回写入成功标志
        return true;
    }
}
